package com.niiwoo.civet.account.service.local.bill;/**
 * Created by DELL on 2017/12/12.
 */

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.niiwoo.civet.account.dao.entity.*;
import com.niiwoo.civet.account.dao.mapper.OrgBillBaseMapperExt;
import com.niiwoo.civet.account.dao.mapper.UserBillBaseMapperExt;
import com.niiwoo.civet.account.dto.bill.BillBase;
import com.niiwoo.civet.account.dto.request.UserBillBaseRequestDTO;
import com.niiwoo.civet.account.enums.BillStatusEnum;
import com.niiwoo.civet.account.enums.BillUserTypeEnum;
import com.niiwoo.civet.account.enums.OrderTypeEnum;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 账户账单表
 *
 * @author xiaoyingping
 * @create 2017-12-12 11:16
 **/
@Service
@Slf4j
public class BillBaseService {

    @Autowired
    private UserBillBaseMapperExt userBillBaseMapperExt;
    @Autowired
    private OrgBillBaseMapperExt orgBillBaseMapperExt;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private AccountService accountService;
    @Autowired
    private BillFacade billFacade;


    /**
     * 新增账单Base
     * @param billBase
     */
    public void addBillBase(BillBase billBase) {
        billBase.setId(snowflakeIdWorker.nextId());
        if(Objects.isNull(billBase.getStatus())){
            billBase.setStatus(BillStatusEnum.SUCCESS.getValue());
        }
        Date nowDate = new Date();
        billBase.setCreateTime(nowDate);
        billBase.setUpdateTime(nowDate);

        BillUserTypeEnum billUserType = BillUserTypeEnum.getEnumByCode(billBase.getBillType());
        if(BillUserTypeEnum.GENERAL == billUserType){
            UserBillBase userBillBase = new UserBillBase();
            BeanUtils.copyProperties(billBase, userBillBase);
            userBillBaseMapperExt.insertSelective(userBillBase);
        }else {
            OrgBillBase orgBillBase = new OrgBillBase();
            BeanUtils.copyProperties(billBase, orgBillBase);
            orgBillBase.setYearMonthDay(FastDateFormat.getInstance("yyyy-MM-dd").format(nowDate));
            orgBillBaseMapperExt.insertSelective(orgBillBase);
        }
    }


    /**
     * 根据billBaseId查询用户账单Base
     * @param billBaseId
     * @param userId
     * @return
     */
    public UserBillBase getUserBillBaseById(Long billBaseId, String userId) {
        Assert.notNull(billBaseId, "billBaseId不能为空");
        Assert.notNull(userId, "userId不能为空");

        UserBillBaseExample example = new UserBillBaseExample();
        UserBillBaseExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(billBaseId);
        criteria.andUserIdEqualTo(userId);
        List<UserBillBase> list = userBillBaseMapperExt.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }

    /**
     * 根据orderId查询用户账单Base
     * @param userId
     * @param orderId
     * @return
     */
    public BillBase getUserBillBaseByOrderId(String userId, String orderId) {
        Assert.notNull(userId, "userId不能为空");
        Assert.notNull(orderId, "orderId");

        UserBillBaseExample example = new UserBillBaseExample();
        UserBillBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andOrderIdEqualTo(orderId);
        List<UserBillBase> list = userBillBaseMapperExt.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        UserBillBase userBillBase = list.get(0);
        return this.convertBillBase(userBillBase);
    }

    /**
     * 根据billBaseId查询机构账单
     * @param billBaseId
     * @param yearMonthDay
     * @return
     */
    public BillBase getOrgBillBaseById(Long billBaseId, String yearMonthDay) {
        OrgBillBaseExample example = new OrgBillBaseExample();
        OrgBillBaseExample.Criteria criteria = example.createCriteria();
        criteria.andIdEqualTo(billBaseId);
        if(StringUtils.isNotEmpty(yearMonthDay)){
            criteria.andYearMonthDayEqualTo(yearMonthDay);
        }

        List<OrgBillBase> orgBillBaseList = orgBillBaseMapperExt.selectByExample(example);
        if (CollectionUtils.isEmpty(orgBillBaseList)) {
            return null;
        }
        return this.convertBillBase(orgBillBaseList.get(0));
    }


    /**
     * 通过订单ID和订单类型获取产生的账单并锁定
     * @param orderId
     * @param orderType
     * @return
     */
    public List<BillBase> queryByOrderIdAndTypeForUpdate(String orderId, OrderTypeEnum orderType){
        Assert.hasLength(orderId, "orderId不能为空");
        Assert.notNull(orderType, "orderType不能为空");

        List<BillBase> billBaseList = new ArrayList<>();
        //用户账单
        List<UserBillBase> userBillBaseList = userBillBaseMapperExt.queryByOrderIdAndTypeForUpdate(orderId,orderType.getCode());
        billBaseList.addAll(userBillBaseList.stream().map(userBillBase -> this.convertBillBase(userBillBase)).collect(Collectors.toList()));

        //机构、平台账单
        List<OrgBillBase> orgBillBaseList = orgBillBaseMapperExt.queryByOrderIdAndTypeForUpdate(orderId,orderType.getCode());
        billBaseList.addAll(orgBillBaseList.stream().map(orgBillBase -> this.convertBillBase(orgBillBase)).collect(Collectors.toList()));

        return billBaseList;
    }


    /**
     * 修改账单状态
     * @param billBase
     * @param newStatusEnum
     */
    public void updateBillBaseStatus(BillBase billBase, BillStatusEnum newStatusEnum) {
        Assert.notNull(billBase,"billBase不能为空");
        Assert.notNull(billBase.getId(),"billBase的id不能为空");

        BillUserTypeEnum billUserType = BillUserTypeEnum.getEnumByCode(billBase.getBillType());
        Assert.notNull(billUserType,"billUserType不能为空");

        if(BillUserTypeEnum.GENERAL == billUserType){
            Assert.notNull(billBase.getUserId(),"billBase的userId不能为空");

            UserBillBaseExample example = new UserBillBaseExample();
            UserBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andIdEqualTo(billBase.getId());
            criteria.andUserIdEqualTo(billBase.getUserId());

            UserBillBase userBillBase = new UserBillBase();
            userBillBase.setStatus(newStatusEnum.getValue());
            userBillBase.setUpdateTime(new Date());
            userBillBaseMapperExt.updateByExampleSelective(userBillBase,example);
        }else {
            Assert.notNull(billBase.getYearMonthDay(),"billBase的yearMonthDay不能为空");

            OrgBillBaseExample example = new OrgBillBaseExample();
            OrgBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andIdEqualTo(billBase.getId());
            criteria.andYearMonthDayEqualTo(billBase.getYearMonthDay());

            OrgBillBase orgBillBase = new OrgBillBase();
            orgBillBase.setStatus(newStatusEnum.getValue());
            orgBillBase.setUpdateTime(new Date());
            orgBillBaseMapperExt.updateByExampleSelective(orgBillBase,example);
        }
    }

    /**
     * 覃江
     * 通过存管流水号和用户ID获取最近的一条账单信息
     * @param requstNo
     * @param userId
     * @return
     */
    public BillBase getAccountBillBaseByRequestNoAndUserId(String requstNo, String userId, Date bizTime){
        Assert.hasLength(requstNo,"requstNo不能为空");

        List<AccountBase> accountList = accountService.listAccountByUserId(userId);
        if(accountList == null){
            return null;
        }

        BillBase billBase = null;
        BillUserTypeEnum userTypeEnum = billFacade.transToBillUserType(accountList.get(0).getAccountRole());
        if(BillUserTypeEnum.GENERAL.getCode().equals(userTypeEnum.getCode())) {
            Assert.notNull(userId,"userId不能为空");

            UserBillBaseExample example = new UserBillBaseExample();
            example.setOrderByClause("create_time");
            UserBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andUserIdEqualTo(userId);
            criteria.andRequestNoEqualTo(requstNo);
            List<UserBillBase> userBillBases = userBillBaseMapperExt.selectByExample(example);
            if (CollectionUtils.isEmpty(userBillBases)) {
                return null;
            }
            //获取第一条的id
            billBase = this.convertBillBase(userBillBases.get(0));
        } else {
            Assert.notNull(bizTime,"bizTime不能为空");
            DateTime bizDateTime = new DateTime(bizTime);
            List<String> yearMonthDays = new ArrayList<>(3);//yearMonthDay设置为3天
            yearMonthDays.add(bizDateTime.toString("yyyy-MM-dd"));
            yearMonthDays.add(bizDateTime.minusDays(1).toString("yyyy-MM-dd"));
            yearMonthDays.add(bizDateTime.plusDays(1).toString("yyyy-MM-dd"));

            OrgBillBaseExample example = new OrgBillBaseExample();
            example.setOrderByClause("create_time");
            OrgBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andUserIdEqualTo(userId);
            criteria.andRequestNoEqualTo(requstNo);
            criteria.andYearMonthDayIn(yearMonthDays);
            List<OrgBillBase> orgBillBases = orgBillBaseMapperExt.selectByExample(example);
            if (orgBillBases == null || orgBillBases.size() <= 0) {
                return null;
            }
            //获取第一条的id
            billBase = this.convertBillBase(orgBillBases.get(0));
        }

        return billBase;
    }

    /**
     * 覃江
     * 通过存管流水号和用户ID获取所有的 accountBase信息
     * @param requstNo 平台流水号
     * @param userId 相关用户id
     * @return
     */
    public List<BillBase> getAccountMultiBillBaseByRequestNoAndUserId(String requstNo, String userId, Date bizTime){
        Assert.hasLength(requstNo,"requstNo不能为空");
        List<BillBase> billBases = new ArrayList<>();
        List<AccountBase> accountList = accountService.listAccountByUserId(userId);
        if(CollectionUtils.isEmpty(accountList)){
            return billBases;
        }

        BillUserTypeEnum userTypeEnum = billFacade.transToBillUserType(accountList.get(0).getAccountRole());
        if(BillUserTypeEnum.GENERAL.getCode().equals(userTypeEnum.getCode())) {
            Assert.notNull(userId,"userId不能为空");

            UserBillBaseExample example = new UserBillBaseExample();
            example.setOrderByClause("create_time");
            UserBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andUserIdEqualTo(userId);
            criteria.andRequestNoEqualTo(requstNo);
            List<UserBillBase> userBillBaseList = userBillBaseMapperExt.selectByExample(example);
            for (UserBillBase userBillBase : userBillBaseList) {
                billBases.add(this.convertBillBase(userBillBase));
            }
        } else {
            Assert.notNull(bizTime,"bizTime不能为空");
            DateTime bizDateTime = new DateTime(bizTime);
            List<String> yearMonthDays = new ArrayList<>(3);//yearMonthDay设置为3天
            yearMonthDays.add(bizDateTime.toString("yyyy-MM-dd"));
            yearMonthDays.add(bizDateTime.minusDays(1).toString("yyyy-MM-dd"));
            yearMonthDays.add(bizDateTime.plusDays(1).toString("yyyy-MM-dd"));

            OrgBillBaseExample example = new OrgBillBaseExample();
            example.setOrderByClause("create_time");
            OrgBillBaseExample.Criteria criteria = example.createCriteria();
            criteria.andUserIdEqualTo(userId);
            criteria.andRequestNoEqualTo(requstNo);
            criteria.andYearMonthDayIn(yearMonthDays);
            List<OrgBillBase> orgBillBases = orgBillBaseMapperExt.selectByExample(example);
            for (OrgBillBase orgBillBase : orgBillBases) {
                billBases.add(this.convertBillBase(orgBillBase));
            }
        }

       return billBases;
    }

    /**
     * 根据条件获取billBase账单列表(分页)
     *
     * @param requestDTO
     * @return
     */
    public PageInfo<UserBillBase> pageBillBase(UserBillBaseRequestDTO requestDTO) {
        UserBillBaseExample example = this.generateAccountBillBaseExample(requestDTO);
        example.setOrderByClause("create_time desc,id desc");

        PageHelper.startPage(requestDTO.getPageNumber(), requestDTO.getPageSize());
        List<UserBillBase> billBaseList = userBillBaseMapperExt.selectByExample(example);
        PageInfo<UserBillBase> pageInfo = new PageInfo<>(billBaseList);

        return pageInfo;
    }

    /**
     * 统计账单金额
     * @param requestDTO
     * @return
     */
    public BigDecimal totalAmount(UserBillBaseRequestDTO requestDTO) {
        UserBillBaseExample example = this.generateAccountBillBaseExample(requestDTO);
        return userBillBaseMapperExt.sumAmountByExample(example);
    }


    /**
     * @param requestDTO
     * @return
     * @Author Jaylin
     * 按照条件返回AccountBillBaseExampleExt对象
     */
    private UserBillBaseExample generateAccountBillBaseExample(UserBillBaseRequestDTO requestDTO) {
        Assert.notNull(requestDTO, "requestDTO不能为空");
        Assert.notNull(requestDTO.getUserId(), "userId不能为空");

        UserBillBaseExample example = new UserBillBaseExample();
        UserBillBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(requestDTO.getUserId());
        if (Objects.nonNull(requestDTO.getAccountId())) {
            criteria.andAccountIdEqualTo(requestDTO.getAccountId());
        }
        if(Objects.nonNull(requestDTO.getOrgId())) {
            criteria.andOrgIdEqualTo(requestDTO.getOrgId());
        }
        if (Objects.nonNull(requestDTO.getProjectId())) {
            criteria.andProjectIdEqualTo(requestDTO.getProjectId());
        }
        if (Objects.nonNull(requestDTO.getInvestId())) {
            criteria.andInvestIdEqualTo(requestDTO.getInvestId());
        }
        if (Objects.nonNull(requestDTO.getGuaranteeId())) {
            criteria.andGuaranteeIdEqualTo(requestDTO.getGuaranteeId());
        }
        if (Objects.nonNull(requestDTO.getInOutType())) {
            criteria.andInoutTypeEqualTo(requestDTO.getInOutType());
        }
        if (Objects.nonNull(requestDTO.getOrderType())) {
            criteria.andOrderTypeEqualTo(requestDTO.getOrderType());
        }
        if (!CollectionUtils.isEmpty(requestDTO.getOrderTypes())) {
            criteria.andOrderTypeIn(requestDTO.getOrderTypes());
        }
        if (Objects.nonNull(requestDTO.getProjectType())) {
            criteria.andProjectTypeEqualTo(requestDTO.getProjectType());
        }
        if (StringUtils.isNotEmpty(requestDTO.getChannelCode())) {
            criteria.andChannelCodeEqualTo(requestDTO.getChannelCode());
        }
        if(Objects.nonNull(requestDTO.getStatus())){
            criteria.andStatusEqualTo(requestDTO.getStatus());
        }
        if (Objects.nonNull(requestDTO.getStartTime()) && Objects.nonNull(requestDTO.getEndTime())) {
            criteria.andCreateTimeBetween(requestDTO.getStartTime(), requestDTO.getEndTime());
        }
        if(Objects.nonNull(requestDTO.getIsBackSpace()) && requestDTO.getIsBackSpace() == true){
            criteria.andBackSourceBillIdIsNotNull();
        }
        if (Objects.nonNull(requestDTO.getIsVisibleEnum())) {
            criteria.andIsVisibleEqualTo(requestDTO.getIsVisibleEnum().getValue());
        }

        return example;
    }




    public BillBase convertBillBase(UserBillBase userBillBase) {
        BillBase billBase = new BillBase();
        BeanUtils.copyProperties(userBillBase,billBase);
        return billBase;
    }

    public BillBase convertBillBase(OrgBillBase orgBillBase) {
        BillBase billBase = new BillBase();
        BeanUtils.copyProperties(orgBillBase,billBase);
        return billBase;
    }

}
